package com.coldlz.mmp.proxy.handlerserver;

import com.coldlz.mmp.common.JacksonUtil;
import com.coldlz.mmp.proxy.*;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Slf4j
public class ConnectHandler extends ChannelInboundHandlerAdapter {
    private final UserContext userContext;

    public ConnectHandler(UserContext userContext) {
        this.userContext = userContext;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object obj) throws Exception {
        if (!(obj instanceof ByteBuf msg)) {
            log.error("unexpected object type");
            userContext.close();
            return;
        }
        UserContext userContext = this.userContext;
        boolean directForward = userContext.isDirectForward();
        ProxyInfo info = userContext.getProxyInfo();
        int parseBeforeIndex = msg.readerIndex();
        info.parse(ctx, msg);
        int parseAfterIndex = msg.readerIndex();

        if (!info.isComplete()) {
            log.error("协议解析异常");
            userContext.close();
            return;
        }
        boolean isConnectReq = info.isConnect();
        ChannelPipeline pipeline = ctx.pipeline();


        // 创建客户端，并 connect 到远程地址
        try {
            RemoteClientFactory.create(userContext);
        } catch (Exception e) {
            log.error("创建客户端异常 {} {}", info.getHost(), info.getPort(), e);
            userContext.close();
            return;
        }

        if (isConnectReq) {
            pipeline.addLast(new ServerEstablishedHandler(userContext));
            // 直接触发一次 established
            ctx.fireChannelRead(msg);
        }

        String getReqPrefix = "GET http://";
        boolean isHttpGET = (info.getProtocolName() == Protocol.HTTP) && info.getContents().get(0).startsWith(getReqPrefix);

        if (directForward) {
            pipeline.addLast(new ServerDirectForwardHandler(userContext));
            // 如果请求是 http 并且是 GET 请求的话，这里直接请求并将响应信息返回回去
            if (isHttpGET) {
                // 需要直接触发一次请求
                msg.readerIndex(parseBeforeIndex);
                pipeline.fireChannelRead(msg);
            }
        } else {
            // 尝试解析协议，如：ws、wss、http、https协议
            pipeline.addLast(new TryParseProtocolHandler(userContext));
        }

        if (!ctx.isRemoved()) {
            pipeline.remove(this);
        }
        if (isHttpGET) {
            msg.readerIndex(parseBeforeIndex);
        } else {
            msg.readerIndex(parseAfterIndex);
        }
        pipeline.fireChannelRead(msg);
        log.info("接收到连接 ====> {}", JacksonUtil.toJsonStr(info));
    }

}